package com.ddc.study.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.ddc.study.R;
import com.ddc.study.simple.SimpleViewHolder;
import com.ddc.study.util.Utils;

import java.util.ArrayList;
import java.util.List;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.ViewPager2;

/**
 * Created on 2018/4/24.
 *
 * @author lshun
 * @version 1.0
 */
public class CyclicViewPager extends FrameLayout {
    private static final String TAG = "CyclicViewPager";

    private static final int DEFAULT_AUTO_SWITCH_INTERVAL = 2500;

    /**
     * 展示轮播内容的ViewPager
     */
    private ViewPager2 mViewPager2;
    private Adapter<Item> mAdapter;
    /**
     * 当前显示的内容的标题
     */
    private TextView mTvTitle;
    /**
     * 指示器布局
     */
    private ViewGroup mIndicatorLayout;

    private ImageView mSelectDotView;
    private List<ImageView> mNormalDotViews;

    private boolean mAutoSwitch;
    private int mAutoSwitchInterval;
    private int mDotSize;

    private final Runnable mAutoSwitchRunnable = new Runnable() {
        @Override
        public void run() {
            mViewPager2.setCurrentItem(mViewPager2.getCurrentItem() + 1);
            postDelayed(this, mAutoSwitchInterval);
        }
    };

    private ViewPager2Indicator indicator;

    public CyclicViewPager(Context context) {
        this(context, null);
    }

    public CyclicViewPager(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CyclicViewPager(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public CyclicViewPager(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);

        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CyclicViewPager);
        mAutoSwitch = array.getBoolean(R.styleable.CyclicViewPager_autoSwitch, true);
        if (!mAutoSwitch) {
            Log.w(TAG, "The auto switch is not enable," +
                    " maybe you should use the default ViewPager2 instead of CyclicViewPager.");
        }
        mAutoSwitchInterval = array.getInt(R.styleable.CyclicViewPager_autoSwitch, DEFAULT_AUTO_SWITCH_INTERVAL);
        mDotSize = array.getDimensionPixelSize(R.styleable.CyclicViewPager_dotSize, Utils.dp2px(getContext(), 6));
        array.recycle();

        LayoutInflater inflater = LayoutInflater.from(context);
        View view = inflater.inflate(R.layout.layout_my_view_pager, this);
        mIndicatorLayout = view.findViewById(R.id.layout_indicator);
        mTvTitle = view.findViewById(R.id.tv_title);
        mViewPager2 = view.findViewById(R.id.view_pager_2);
        mAdapter = new Adapter<>();
        mViewPager2.setAdapter(mAdapter);
        mViewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
            @Override
            public void onPageSelected(int position) {
                updateTitle(position);
                freshDotLayout();
            }

            @Override
            public void onPageScrollStateChanged(@ViewPager2.ScrollState int state) {
                if (state != ViewPager2.SCROLL_STATE_IDLE) return;
                int mCurrentPosition = mViewPager2.getCurrentItem();
                if (mCurrentPosition < mAdapter.getCacheSize()) {
                    mViewPager2.setCurrentItem(mCurrentPosition + mAdapter.getData().size(), false);
                } else if (mCurrentPosition >= mAdapter.getItemCount() - mAdapter.getCacheSize()) {
                    mViewPager2.setCurrentItem(mCurrentPosition - mAdapter.getData().size(), false);
                }
            }
        });

        indicator = view.findViewById(R.id.view_pager_2_indicator);
        indicator.setupWithViewPager2(mViewPager2);

        mSelectDotView = (ImageView) inflater.inflate(R.layout.item_dot, mIndicatorLayout, false);
        ViewGroup.LayoutParams lp = mSelectDotView.getLayoutParams();
        lp.width = mDotSize;
        lp.height = mDotSize;
        //mSelectDotView.setLayoutParams(lp);
        mSelectDotView.setBackgroundResource(R.drawable.dot_selected_style);

        mNormalDotViews = new ArrayList<>();
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean ret = super.dispatchTouchEvent(ev);
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.e(TAG, "dispatchTouchEvent ACTION_DOWN -> " + ret);
                getParent().requestDisallowInterceptTouchEvent(true);
                removeCallbacks(mAutoSwitchRunnable);
                break;
            case MotionEvent.ACTION_UP:
                Log.e(TAG, "dispatchTouchEvent ACTION_UP -> " + ret);
                postDelayed(mAutoSwitchRunnable, mAutoSwitchInterval);
                break;
            case MotionEvent.ACTION_MOVE:
                Log.e(TAG, "dispatchTouchEvent ACTION_MOVE -> " + ret);
                break;
        }
        return ret;
    }

    private OnItemClickListener mItemClickListener;
    private final OnClickListener mOnClickListener = new OnClickListener() {
        @Override
        public void onClick(View v) {
            if (mItemClickListener != null) {
                mItemClickListener.onItemClick(getCurrentItem());
            }
        }
    };

    public void setOnItemClickListener(@Nullable OnItemClickListener l) {
        mItemClickListener = l;
        mAdapter.setListener(mOnClickListener);
    }

    public interface OnItemClickListener {
        void onItemClick(int position);
    }

    /**
     * 为控件设置新的数据, 然后会选中新数据的第一个(若存在)
     *
     * @param data 数据内容
     */
    public void setNewData(@Nullable List<Item> data) {
        mAdapter.setNewData(data);
        if (data != null && !data.isEmpty()) {
            updateDotLayout(data.size());
            mViewPager2.setCurrentItem(mAdapter.getCacheSize());
        }
        indicator.setupWithViewPager2(mViewPager2);
    }

    /**
     * 数据变更后调整dotLayout的视图
     *
     * @param size 新数据的大小
     */
    private void updateDotLayout(int size) {
        mIndicatorLayout.removeAllViews();
        if (size <= 0) return;
        mIndicatorLayout.addView(mSelectDotView);

        //根据新旧点的数量判断是inflate view 还是 remove view
        int temp = mNormalDotViews.size() - size + 1;
        if (temp > 0) {
            while (temp-- > 0) {
                mNormalDotViews.remove(0);
            }
        } else if (temp < 0) {
            LayoutInflater inflater = LayoutInflater.from(getContext());
            while (temp++ < 0) {
                ImageView iv = (ImageView) inflater.inflate(R.layout.item_dot, mIndicatorLayout, false);
                iv.setMinimumHeight(mDotSize);
                iv.setMaxWidth(mDotSize);
                iv.setBackgroundResource(R.drawable.dot_normal_style);
                mNormalDotViews.add(iv);
            }
        }

        for (View view : mNormalDotViews) {
            mIndicatorLayout.addView(view);
        }
    }

    private void updateTitle(int position) {
        mTvTitle.setText(mAdapter.getPageTitle(position));
    }

    /**
     * 更新小点布局
     */
    private void freshDotLayout() {
        if (mIndicatorLayout.equals(mSelectDotView.getParent())) {
            mIndicatorLayout.removeView(mSelectDotView);
            mIndicatorLayout.addView(mSelectDotView, getCurrentItem());
        } else {
            throw new IllegalStateException("The current selected dot view is not add to dot layout!");
        }
    }

    public int getCurrentItem() {
        final int size = mAdapter.getData().size();
        return (mViewPager2.getCurrentItem() - mAdapter.getCacheSize() + size) % size;
    }

    @Override
    protected void onAttachedToWindow() {
        Log.e(TAG, "onAttachedToWindow ->");
        super.onAttachedToWindow();
        if (mAutoSwitch) {
            postDelayed(mAutoSwitchRunnable, mAutoSwitchInterval);
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        Log.e(TAG, "onDetachedFromWindow ->");
        super.onDetachedFromWindow();
        removeCallbacks(mAutoSwitchRunnable);
    }

    public static class Adapter<T extends Item> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
        private int mCacheSize;//首尾缓冲的数量(数据小于2条时为0, 大于2时为2)
        private final List<T> mHeaderData = new ArrayList<>();
        private final List<T> mFooterData = new ArrayList<>();
        @NonNull
        private List<T> mData = new ArrayList<>();
        @Nullable
        private OnClickListener mListener;

        @NonNull
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            LayoutInflater inflater = LayoutInflater.from(parent.getContext());
            View itemView = inflater.inflate(R.layout.layout_view_pager, parent, false);
            DataBindingUtil.bind(itemView);
            return new SimpleViewHolder(itemView);
        }

        @Override
        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
            ImageView iv = holder.itemView.findViewById(R.id.iv_content);
            T item = getItem(position);
            if (item == null) {
                iv.setImageDrawable(null);
                iv.setTag(null);
                holder.itemView.setOnClickListener(null);
            } else {
                Glide.with(iv)
                        .load(item.getImageUrl())
                        .placeholder(R.mipmap.loading)
                        .error(R.mipmap.failed)
                        .into(iv);
                holder.itemView.setOnClickListener(v -> {
                    if (mListener != null) {
                        mListener.onClick(v);
                    }
                });
            }
        }

        private T getItem(int position) {
            if (position < mCacheSize) {
                return mHeaderData.get(position);
            } else if (position - mCacheSize < mData.size()) {
                return mData.get(position - mCacheSize);
            } else {
                return mFooterData.get(position - mCacheSize - mData.size());
            }
        }

        @Override
        public int getItemCount() {
            return mHeaderData.size() + mFooterData.size() + mData.size();
        }

        void setListener(@Nullable OnClickListener listener) {
            mListener = listener;
        }

        void setNewData(@Nullable List<T> data) {
            setData(data);
            notifyDataSetChanged();
        }

        @NonNull
        List<T> getData() {
            return mData;
        }

        int getCacheSize() {
            return mCacheSize;
        }

        private void setData(@Nullable List<T> data) {
            if (data == null) {
                mData = new ArrayList<>();
                mCacheSize = 0;
            } else {
                mData = data;
                mHeaderData.clear();
                mFooterData.clear();

                int size = data.size();
                if (size < 2) {
                    mCacheSize = 0;
                } else {
                    mCacheSize = 2;
                    mHeaderData.add(data.get(size - 2));
                    mHeaderData.add(data.get(size - 1));
                    mFooterData.add(data.get(0));
                    mFooterData.add(data.get(1));
                }
            }
        }

        CharSequence getPageTitle(int position) {
            return getItem(position).getTitle();
        }
    }

    public static class Item {
        private String mTitle;
        private String mImageUrl;
        private String mClickUrl;

        public void setTitle(String title) {
            mTitle = title;
        }

        public String getTitle() {
            return mTitle;
        }

        public String getImageUrl() {
            return mImageUrl;
        }

        public void setImageUrl(String imageUrl) {
            mImageUrl = imageUrl;
        }

        public String getClickUrl() {
            return mClickUrl;
        }

        public void setClickUrl(String clickUrl) {
            mClickUrl = clickUrl;
        }
    }
}
